package com.eastfair.builder.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.annotation.annotation.cache.Cache;
import com.eastfair.annotation.annotation.cache.Magic;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.builder.dao.ConstructionPersonnelMapper;
import com.eastfair.builder.dao.ReportSpaceMapper;
import com.eastfair.builder.dto.ConstructionPersonnelDTO;
import com.eastfair.builder.entity.ConstructionPersonnel;
import com.eastfair.builder.entity.ReportSpace;
import com.eastfair.builder.enumeration.ConstructionPersonnelGenderEnum;
import com.eastfair.builder.enumeration.ConstructionPersonnelWorkTypeEnum;
import com.eastfair.builder.exceptioncode.BuilderExceptionCode;
import com.eastfair.builder.service.ConstructionPersonnelService;
import com.eastfair.builder.vo.ConstructionPersonnelVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.database.mybatis.conditions.Wraps;
import com.eastfair.database.mybatis.conditions.query.QueryWrap;
import com.eastfair.database.mybatis.typehandler.TypeHandlerUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.*;

/**
 * <p>
 * 业务实现类
 * 施工人员信息
 * </p>
 *
 * @author linan
 * @date 2023-05-04
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ConstructionPersonnelServiceImpl extends SuperServiceImpl<ConstructionPersonnelMapper, ConstructionPersonnel> implements ConstructionPersonnelService {

    public static final int INT_20 = 20;
    public static final int INT_18 = 18;
    @Resource
    private ReportSpaceMapper reportSpaceMapper;

    @Override
    protected R<Boolean> handlerSave(ConstructionPersonnel model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }
    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ConstructionPersonnel> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }


    /**
     * 通用查询
     *
     * @param modelDTO DTO
     * @param ids      主键id集合
     * @return list
     */
    @Override
    public List<ConstructionPersonnel> list(ConstructionPersonnelDTO modelDTO, List<Long> ids) {
        return ((ConstructionPersonnelService) AopContext.currentProxy()).listOfCache(modelDTO, ids);
    }


    /**
     * 缓存查询
     *
     * @param modelDTO DTO
     * @param ids      主键id集合
     * @return list
     */
    @Override
    @Cache(key = "",
            magic = @Magic(
                    key = "{" +
                            "{'isEnabled', #args[0]?.isEnabled}," +
                            "{'name', #args[0]?.name}," +
                            "{'gender', #args[0]?.gender}," +
                            "{'cardNumber', #args[0]?.cardNumber}," +
                            "{'workType', #args[0]?.workType}," +
                            "{'id', #args[1]}" +
                            "}"))
    public List<ConstructionPersonnel> listOfCache(ConstructionPersonnelDTO modelDTO, List<Long> ids) {
        //查询
        ConstructionPersonnel queryModel = new ConstructionPersonnel();
        if (modelDTO != null) {
            BeanUtils.copyProperties(modelDTO, queryModel);
        }
        QueryWrap<ConstructionPersonnel> wrapper = Wraps.q(queryModel);
        if (ids != null && !ids.isEmpty()) {
            wrapper.lambda().in(ConstructionPersonnel::getId, ids);
        }
        //添加其他业务查询条件
        wrapper.lambda().eq(ConstructionPersonnel::getIsDeleted, BusinessConstant.DELETE_NO);
        List<ConstructionPersonnel> modelList = list(wrapper);
        return modelList;
    }
    
    @Override
    public Boolean addConstructionPersonnel(ConstructionPersonnelDTO constructionPersonnelDTO) {
        ReportSpace reportSpace = reportSpaceMapper.selectById(constructionPersonnelDTO.getReportSpaceId());
        String cardNumber = constructionPersonnelDTO.getCardNumber();
        if (StrUtil.isNotBlank(constructionPersonnelDTO.getCardNumber())) {
            String cryptCardNumber = TypeHandlerUtil.crypt(cardNumber);
            constructionPersonnelDTO.setCardNumber(cryptCardNumber);
        }
        if(Objects.nonNull(reportSpace)){
            QueryWrapper<ConstructionPersonnel> constructionPersonnelQueryWrapper = new QueryWrapper<>();
            // 判断身份证号是否在该展会下已存在 （同一展会 不能乱窜）
            constructionPersonnelQueryWrapper
                    .eq("a.is_deleted",BusinessConstant.DELETE_NO)
                    .eq("b.is_deleted",BusinessConstant.DELETE_NO)
                    .eq("a.card_number",constructionPersonnelDTO.getCardNumber())
                    .eq("b.exhibition_id",reportSpace.getExhibitionId());
            List<ConstructionPersonnelVO> constructionPersonnelVOS = baseMapper.queryConstructionPersonnel(constructionPersonnelQueryWrapper);
            if(constructionPersonnelVOS.size()>0){
                throw BizException.wrap(BuilderExceptionCode.CARD_NUMBER_EXIST);
            }
            constructionPersonnelDTO.setCardNumber(cardNumber);
            return save(BeanUtil.copyProperties(constructionPersonnelDTO,ConstructionPersonnel.class));
        }
        return false;
    }

    @Override
    public List<ConstructionPersonnelVO> queryConstructionPersonnel(ConstructionPersonnelDTO constructionPersonnelDTO) {
        List<ConstructionPersonnel> list = list(new QueryWrapper<ConstructionPersonnel>().lambda()
                .eq(ConstructionPersonnel::getIsDeleted, BusinessConstant.NO)
                .eq(ConstructionPersonnel::getReportSpaceId, constructionPersonnelDTO.getReportSpaceId()));
        return ConvertUtil.convertList(list,ConstructionPersonnelVO.class);
    }

    @Override
    public List<ConstructionPersonnel> listByReportSpaceId(Long reportSpaceId) {
        return list(new QueryWrapper<ConstructionPersonnel>().lambda()
                .eq(ConstructionPersonnel::getIsDeleted, BusinessConstant.NO)
                .eq(ConstructionPersonnel::getReportSpaceId, reportSpaceId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean importConstructionPersonnel(MultipartFile file, Long reportSpaceId) throws Exception{
        if (file == null) {
            throw BizException.wrap(-1, "未上传文件");
        }
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<Map<String, Object>> importList = reader.readAll();
        if (importList == null || importList.isEmpty()) {
            throw BizException.wrap(-1, "读取数据为空");
        }
        for (int i = 0; i < importList.size(); i ++) {
            int rowIndex = i + 2;
            Map<String, Object> map = importList.get(i);
            ConstructionPersonnelDTO constructionPersonnelDTO = new ConstructionPersonnelDTO();
            constructionPersonnelDTO.setReportSpaceId(reportSpaceId);
            map.forEach((k,v)->{
                if(Objects.isNull(v) || io.seata.common.util.StringUtils.isBlank(v.toString())){
                    throw BizException.wrap(-1, "第" + rowIndex + "行，" + k + "为空");
                }else {
                    dealVO(constructionPersonnelDTO, k, v);
                }
            });
            addConstructionPersonnel(constructionPersonnelDTO);
        }
        return true;
    }

    @Override
    public List<ConstructionPersonnelVO> queryConstructionPersonnelBySiteName(ConstructionPersonnelDTO constructionPersonnelDTO) {
        ReportSpace reportSpace = reportSpaceMapper.selectOne(new QueryWrapper<ReportSpace>().lambda()
                .eq(ReportSpace::getIsDeleted, BusinessConstant.NO)
                .eq(ReportSpace::getExhibitionId, constructionPersonnelDTO.getExhibitionId())
                .eq(ReportSpace::getBuilderId, constructionPersonnelDTO.getBuilderId())
                .eq(ReportSpace::getSiteName, constructionPersonnelDTO.getSiteName()));
        if(Objects.nonNull(reportSpace)){
            constructionPersonnelDTO.setReportSpaceId(reportSpace.getId());
            return queryConstructionPersonnel(constructionPersonnelDTO);
        }
        return new ArrayList<>();
    }

    @Override
    public List<ConstructionPersonnelVO> queryConstructionPersonnelByExhibition(ConstructionPersonnelDTO constructionPersonnelDTO) {
        if (StrUtil.isNotBlank(constructionPersonnelDTO.getCardNumber())) {
            String cryptCardNumber = TypeHandlerUtil.crypt(constructionPersonnelDTO.getCardNumber());
            constructionPersonnelDTO.setCardNumber(cryptCardNumber);
        }
        QueryWrapper<ConstructionPersonnel> constructionPersonnelQueryWrapper = new QueryWrapper<>();
        // 判断身份证号是否在该展会下已存在 （同一展会 不能乱窜）
        constructionPersonnelQueryWrapper
                .eq("a.is_deleted", BusinessConstant.DELETE_NO)
                .eq("b.is_deleted", BusinessConstant.DELETE_NO)
                .eq(Objects.nonNull(constructionPersonnelDTO.getCardNumber()),"a.card_number", constructionPersonnelDTO.getCardNumber())
                .eq(Objects.nonNull(constructionPersonnelDTO.getBuilderId()),"b.builder_id", constructionPersonnelDTO.getBuilderId())
                .eq(Objects.nonNull(constructionPersonnelDTO.getSiteName()),"b.site_name", constructionPersonnelDTO.getSiteName())
                .eq("b.exhibition_id", constructionPersonnelDTO.getExhibitionId());
        List<ConstructionPersonnelVO> constructionPersonnelVOS = baseMapper.queryConstructionPersonnel(constructionPersonnelQueryWrapper);
        for (ConstructionPersonnelVO constructionPersonnelVO : constructionPersonnelVOS) {
            if(ConstructionPersonnelWorkTypeEnum.HIGH_ALTITUDE_WORK_PERMIT.getCode().equals(constructionPersonnelVO.getWorkType())){
                constructionPersonnelVO.setWorkType("HIGH_ALTITUDE_WORK");
            }else if(ConstructionPersonnelWorkTypeEnum.ELECTRICIAN_CERT.getCode().equals(constructionPersonnelVO.getWorkType())){
                constructionPersonnelVO.setWorkType("TEST_PANEL");
            }else if(ConstructionPersonnelWorkTypeEnum.OTHER.getCode().equals(constructionPersonnelVO.getWorkType())){
                constructionPersonnelVO.setWorkType("OTHER");
            }
        }
        return constructionPersonnelVOS;
    }

    @Override
    public Boolean checkConstructionPersonnel(ConstructionPersonnelDTO constructionPersonnelDTO) {
        if (StrUtil.isNotBlank(constructionPersonnelDTO.getCardNumber())) {
            String cryptCardNumber = TypeHandlerUtil.crypt(constructionPersonnelDTO.getCardNumber());
            constructionPersonnelDTO.setCardNumber(cryptCardNumber);
        }
        QueryWrapper<ConstructionPersonnel> constructionPersonnelQueryWrapper = new QueryWrapper<>();
        // 判断身份证号是否在该展会下已存在 （同一展会 不能乱窜）
        constructionPersonnelQueryWrapper
                .eq("a.is_deleted", BusinessConstant.DELETE_NO)
                .eq("b.is_deleted", BusinessConstant.DELETE_NO)
                .eq("a.card_number", constructionPersonnelDTO.getCardNumber())
                .eq("b.exhibition_id", constructionPersonnelDTO.getExhibitionId());
        List<ConstructionPersonnelVO> constructionPersonnelVOS = baseMapper.queryConstructionPersonnel(constructionPersonnelQueryWrapper);
        return constructionPersonnelVOS.size() > 0;
    }

    private void dealVO(ConstructionPersonnelDTO constructionPersonnelDTO, String k, Object v) {
        switch (k) {
            case "姓名":
                if(v.toString().length() > INT_20){
                    throw BizException.wrap(BuilderExceptionCode.NAME_MORE_THAN_20);
                }
                constructionPersonnelDTO.setName(v.toString());
                break;
            case "性别":
                constructionPersonnelDTO.setGender(ConstructionPersonnelGenderEnum.matchByDesc(v.toString()));
                break;
            case "身份证号":
                if(v.toString().length() != INT_18){
                    throw BizException.wrap(BuilderExceptionCode.CARD_NUMBER_ERROR);
                }
                constructionPersonnelDTO.setCardNumber(v.toString());
                break;
            case "工种":
                constructionPersonnelDTO.setWorkType(ConstructionPersonnelWorkTypeEnum.matchByDesc(v.toString()));
                break;
            default:
                break;
        }
    }

    /**
     * do转vo
     *
     * @param model model
     * @return modelVo
     */
    @Override
    public ConstructionPersonnelVO doToVo(ConstructionPersonnel model) {
        ConstructionPersonnelVO modelVo = new ConstructionPersonnelVO();
        BeanUtils.copyProperties(model, modelVo);
        modelVo.setId(model.getId());
        return modelVo;
    }

    /**
     * do转vo
     *
     * @param modelList modelList
     * @return list
     */
    @Override
    public List<ConstructionPersonnelVO> doToVos(List<ConstructionPersonnel> modelList) {
        if (modelList == null || modelList.isEmpty()) {
            return null;
        }
        List<ConstructionPersonnelVO> result = new ArrayList<>();
        for (ConstructionPersonnel model : modelList) {
            result.add(doToVo(model));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByReportSpaceId(Long reportSpaceId) {
        List<ConstructionPersonnel> list = listByReportSpaceId(reportSpaceId);
        if (list == null || list.isEmpty()) {
            return false;
        }
        return removeByIdsOfLogic(list);
    }
}
